import { SortUtils } from "../../api/math/SortUtils";
import { E_GameBaseAttr } from "../defs/com/E_GameBaseAttr";
import { E_ItemType } from "../defs/item/E_ItemType";
import { E_PetGlobal } from "../defs/pet/E_PetGlobal";
import { E_PetMonsterConfigIndex } from "../defs/pet/E_PetMonsterConfigIndex";
import { E_PetPos } from "../defs/pet/E_PetPos";
import { E_PetRare } from "../defs/pet/E_PetRare";
import { E_PlayerIncID } from "../defs/player/E_PlayerIncID";
import { CDMath } from "../excel/CDMath";
import { CDMonster, E_CDMonster } from "../excel/CDMonster";
import { CDPet } from "../excel/CDPet";
import { CDPetGlobal } from "../excel/CDPetGlobal";
import { CDPetLv } from "../excel/CDPetLv";
import { CDPetRank } from "../excel/CDPetRank";
import { CDPetTeamUnlock } from "../excel/CDPetTeamUnlock";
import { CEMath } from "../excel_extend/CEMath";
import { Pet } from "../struct/Pet";
import { Player } from "../struct/Player";
import { LanguageUtils } from "../../utils/LanguageUtils";
import { SDBattle } from "./SDBattle";
import { SDFuction } from "./SDFuction";
import { SDHandBook } from "./SDHandBook";
import { SDPlayer } from "./SDPlayer";

/**
 * 数据-宠物
 */
export abstract class SDPet {

    /**
     * 获取宠物名
     * @param pet 
     * @param player 
     * @returns 
     */
    public static getPetName(pet: Pet | CDPet | number, player?: Player): string|null {
        let config: CDPet|null = null;
        if (pet instanceof Pet) {
            config = CDPet.getData(pet.configId);
        }
        else if (pet instanceof CDPet) {
            config = pet;
        }
        else if (player) {
            const p = player.petManager.getPet(pet);
            if (p) {
                config = CDPet.getData(p.configId);
            }
        }
        if (config) {
            return LanguageUtils.getV(config.name);
        }
        return null;
    }


    /**
     * 获取spine路径
     * @param pet 
     * @param player 
     */
    public static getSpineUrl(pet: Pet | CDPet | number, player?: Player): string|null {
        let config: CDPet|null = null;
        if (pet instanceof Pet) {
            config = CDPet.getData(pet.configId);
        }
        else if (pet instanceof CDPet) {
            config = pet;
        }
        else if (player) {
            const p = player.petManager.getPet(pet);
            config = CDPet.getData(p.configId);
        }
        if (config) {
            return config.model + '/' + config.model;
        }
        return null;
    }


    /**
     * 获取宠物背包格子数
     * @param player 
     */
    public static getBagCapacity(player: Player): number {
        const basev = CDPetGlobal.getData(E_PetGlobal.BagCapacity).value;
        const levelv = CDPetGlobal.getData(E_PetGlobal.BagLvCapacity).value;
        const levelAdd = player.petManager.bagLevel * levelv;
        return basev + levelAdd;
    }


    /**
     * 宠物达到最大等级
     * @param pet 
     */
    public static isPetLevelMax(pet: Pet): boolean {
        const ks = CDPetLv.datas.getKeys();
        const maxv = ks[ks.length - 1];
        return pet && pet.petLevel >= maxv;
    }



    /**
     * 宠物达到最大进阶
     * @param pet 
     */
    public static isPetEvolutionMax(pet: Pet): boolean {
        const ks = CDPetRank.datas.getKeys();
        const maxv = ks[ks.length - 1];
        return pet && pet.evolutionLevel >= maxv;
    }


    /**
     * 最大觉醒等级
     * @param pet 
     * @returns 
     */
    public static getMaxWakeLevel(player: Player, pet: Pet): number {
        const defaultMaxLevel = 200;
        if (!pet || !player) {
            return defaultMaxLevel;
        }

        const petConfig = CDPet.getData(pet.configId);
        if (!petConfig) {
            return defaultMaxLevel;
        }

        const maxv = CEMath.getPetWakeLevelMax(petConfig.wakeMath);
        return maxv;
    }


    /**
     * 宠物达到最大进阶
     * @param player 
     * @param pet 
     * @returns 
     */
    public static isPetWakeMax(player: Player, pet: Pet): boolean {
        const maxWakeLv = this.getMaxWakeLevel(player, pet);
        return pet.wakeLevel >= maxWakeLv;
    }


    /**
     * 获取指定类型的id
     * @param player 
     * @param pos 
     * @param sortType 0-不排序 其他-上阵状态>排序方式 （1-稀有度，2-等级）>id
     * @param idList 
     * @param filterFight 0-不过滤，-1-反向过滤，1-过滤
     * @param filterLock 0-不过滤，-1-反向过滤，1-过滤
     * @returns 
     */
    public static getIdList(player: Player, pos: E_PetPos, sortType = 0, idList: number[] = [], filterFight = 0, filterLock = 0): number[] {
        const pm = player.petManager;
        const vs = pm.getPetValues();

        idList.length = 0;

        for (let i = 0, len = vs.length; i < len; i++) {
            const config = CDPet.getData(vs[i].configId);
            if (!config || (config.position !== pos && pos !== 0)) {
                continue;
            }
            if (0 !== filterLock) {
                if ((vs[i].lock && filterLock === 1) || (!vs[i].lock && filterLock === -1)) {
                    continue;
                }
            }
            if (0 !== filterFight) {
                if ((vs[i].fightPos === 0 && filterFight === -1) || (vs[i].fightPos > 0 && filterFight === 1)) {
                    continue;
                }
            }
            idList.push(vs[i].petId);
        }

        if (sortType !== 0) {
            SortUtils.quickSort(idList, (id1: number, id2: number) => {
                const p1 = pm.getPet(id1);
                const p2 = pm.getPet(id2);

                //出战标志
                if (p1.fightPos !== p2.fightPos) {
                    return p1.fightPos > 0 ? -1 : 1;
                }

                const c1 = CDPet.getData(p1.configId);
                const c2 = CDPet.getData(p2.configId);

                //等级 or 稀有度
                if (sortType === 1) {
                    if (c1.rare !== c2.rare) {
                        return c1.rare > c2.rare ? -1 : 1;
                    }
                    if (p1.petLevel !== p2.petLevel) {
                        return p1.petLevel > p2.petLevel ? -1 : 1;
                    }
                }
                else {
                    if (p1.petLevel !== p2.petLevel) {
                        return p1.petLevel > p2.petLevel ? -1 : 1;
                    }
                    if (c1.rare !== c2.rare) {
                        return c1.rare > c2.rare ? -1 : 1;
                    }
                }
                if (c1.id !== c2.id) {
                    return c1.id < c2.id ? -1 : 1;
                }
                //id
                return id1 - id2;
            });
        }

        return idList;
    }


    /**
    * 获取宠物基础属性ID
    * @param player 
    * @param petID 
    * @returns 
    */
    public static getBaseMathID(player: Player, petID: number): number {
        const pet = player.petManager.getPet(petID);
        if (pet) {
            const petConfig = CDPet.getData(pet.configId);
            if (petConfig) {
                return petConfig.baseMath + pet.petLevel;
            }
        }
        return 0;
    }


    /**
     * 获取宠物天赋属性ID
     * @param player 
     * @param petID 
     * @returns 
     */
    public static getTalentMathID(player: Player, petID: number): number {
        const pet = player.petManager.getPet(petID);
        if (pet) {
            const petConfig = CDPet.getData(pet.configId);
            if (petConfig) {
                return petConfig.talentMath + pet.evolutionLevel;
            }
        }
        return 0;
    }


    /**
    * 获取宠物觉醒属性ID
    * @param player 
    * @param petID 
    * @returns 
    */
    public static getWakeMathID(player: Player, petID: number): number {
        const pet = player.petManager.getPet(petID);
        if (pet) {
            const petConfig = CDPet.getData(pet.configId);
            if (petConfig) {
                return petConfig.wakeMath + pet.wakeLevel;
            }
        }
        return 0;
    }


    /**
     * 添加宠物属性
     * @param player 
     * @param petId 
     * @param outList 
     * @param ratio
     * @returns 
     */
    public static addPetBaseAttrs(
        player: Player,
        petId: number,
        outList?: number[],
        ratio = 1
    ): number[] {

        outList = outList || [];
        for (let i = 0, len = E_GameBaseAttr.EnumCount; i < len; i++) {
            outList[i] = outList[i] || 0;
        }

        const pet = player.petManager.getPet(petId);
        if (!pet) {
            return outList;
        }

        const config = CDPet.getData(pet.configId);
        if (!config) {
            return outList;
        }

        //修改这边同步修改下边的 loadBattleDataByMonsterConfig
        SDPlayer.addMathConfig(CDMath.getData(config.baseMath + pet.petLevel), outList, ratio);
        SDPlayer.addMathConfig(CDMath.getData(config.talentMath + pet.evolutionLevel), outList, ratio);
        SDPlayer.addMathConfig(CDMath.getData(config.wakeMath + pet.wakeLevel), outList, ratio);

        return outList;
    }


    /**
    * 获取战力
    * @param player 
    * @param petId 
    */
    public static getFightScore(player: Player, petId: number): number {
        const pet = player.petManager.getPet(petId);
        if (!pet) {
            return 0;
        }

        const list: number[] = [];
        this.addPetBaseAttrs(player, petId, list);
        const score = SDBattle.getFightScore(list);

        return Math.floor(score);
    }


    /**
     * 获取最大上阵位数
     * @returns 
     */
    public static getMaxFightPos(): number {
        const ks = CDPetTeamUnlock.datas.getKeys();
        const maxIdx = ks[ks.length - 1];
        return maxIdx;
    }


    /**
     * 阵型位置是否开启
     * @param player 
     * @param index 
     * @returns 
     */
    public static isFightPosOpen(player: Player, index: number): boolean {
        //功能是否开启
        const config = CDPetTeamUnlock.getData(index);
        if (config) {
            const unlock = SDFuction.isUnlock(player, config.unlockid);
            return unlock;
        }
        return true;
    }


    /**
     * 获取制定阵位的宠物
     * @param player 
     * @param index 
     */
    public static getFightPosPet(player: Player, index: number): Pet|null {
        const pm = player.petManager;
        const vs = pm.getFightingValues();
        const idx = vs.indexOf(index);
        if (idx >= 0) {
            const ks = pm.getFightingKeys();
            return pm.getPet(ks[idx]);
        }
        return null;
    }


    /**
     * 获取解锁描述
     * @param player 
     * @param index 
     */
    public static getFightPosUnlockString(player: Player, index: number): string {
        const config = CDPetTeamUnlock.getData(index);
        if (config) {
            const unlock = SDFuction.getFunctionUnlockString(player, config.unlockid);
            return unlock;
        }
        return '即将开放，敬请期待';
    }


    /**
     * 通过配置id获取宠物
     * @param player 
     * @param configId 
     * @param ignoreLost 忽略拥有过又丢失
     * @returns -1-无，其他-宠物id or 配置id
     */
    public static getPetIdByConfigId(player: Player, configId: number, ignoreLost = true): number {
        const list = player.petManager.getPetValues();
        for (let i = list.length - 1; i >= 0; i--) {
            if (list[i].configId === configId) {
                return list[i].petId;
            }
        }

        if (!ignoreLost && player.petManager.getOwnedList().indexOf(configId) >= 0) {
            return configId;
        }

        return -1;
    }

    /**
    * 通过配置id获取宠物
    * @param player 
    * @param configId 
    * @returns 
    */
    public static getPetByConfigId(player: Player, configId: number): Pet|null {
        const list = player.petManager.getPetValues();
        for (let i = list.length - 1; i >= 0; i--) {
            if (list[i].configId === configId) {
                return list[i];
            }
        }

        return null;
    }


    /**
    * 创建新宠物
    * @returns 
    */
    public static createNew(player: Player, configId: number): Pet|null {
        const config = CDPet.getData(configId);
        if (!config) {
            return null;
        }

        const pet = Pet.create();
        pet.petId = player ? SDPlayer.getUniqueIndex(player, E_PlayerIncID.Pet) : -1;
        pet.configId = configId;
        pet.petLevel = 1;
        pet.wakeLevel = 1;
        pet.evolutionLevel = 1; //TODO

        if (player) {
            player.petManager.putPet(pet.petId, pet);
            if (-1 === player.petManager.getOwnedList().indexOf(configId)) {
                player.petManager.addOwned(configId);
            }
            SDHandBook.checkId(player, E_ItemType.Pet, configId);
        }

        if (config.rare >= E_PetRare.Best) {
            pet.lock = true;
        }

        pet.quality = config.color;

        return pet;
    }


    /**
     * 获取宠物技能
     * @param monster 
     * @param skillIdLevels 
     * @param addActive 统计主动技能
     * @param addNative 统计被动技能
     * @returns 
     */
    public static addPetSkillIdLevelByMonsterConfig(
        monster: CDMonster | number,
        skillIdLevels: number[],
        addActive = false,
        addNative = true
    ): number[] {

        skillIdLevels = skillIdLevels || [];

        if (!addActive && !addNative) {
            return skillIdLevels;
        }

        const monsterConfig = (monster instanceof CDMonster) ? monster : CDMonster.getData(monster);

        for (let i = E_CDMonster.pet_1; i <= E_CDMonster.pet_4; i++) {
            const petConfigList: number[] = monsterConfig.getAttr(i);
            this.addPetSkillIdLevelByPetConfigList(petConfigList, skillIdLevels, addActive, addNative);
        }

        return skillIdLevels;
    }


    /**
    * 获取宠物技能
    * @param petConfigList 
    * @param skillIdLevels 
    * @param addActive 统计主动技能
    * @param addNative 统计被动技能
    * @returns 
    */
    private static addPetSkillIdLevelByPetConfigList(
        petConfigList: number[],
        skillIdLevels: number[],
        addActive = false,
        addNative = true
    ): void {

        if (!addActive && !addNative) {
            return;
        }

        if (petConfigList.length !== E_PetMonsterConfigIndex.EnumCount) {
            return;
        }

        const petConfig = CDPet.getData(petConfigList[E_PetMonsterConfigIndex.PetConfigId]);
        if (!petConfig) {
            return;
        }

        //主动
        if (addActive) {
            const lv1 = petConfigList[E_PetMonsterConfigIndex.SkillLevel_1];
            if (petConfig && petConfig.nomarlSkill > 0 && lv1 > 0) {
                skillIdLevels.push(petConfig.nomarlSkill, lv1);
            }
        }

        //被动
        if (addNative
            && petConfig.passiveSkill.length > 0) {

            const lv2 = petConfigList[E_PetMonsterConfigIndex.SkillLevel_2];
            if (lv2 > 0 && petConfig.passiveSkill[0] > 0) {
                skillIdLevels.push(petConfig.passiveSkill[0], lv2);
            }

            if (petConfig.passiveSkill.length > 1
                && petConfig.passiveSkill[1] > 0) {
                const lv3 = petConfigList[E_PetMonsterConfigIndex.SkillLevel_3];
                if (lv3 > 0) {
                    skillIdLevels.push(petConfig.passiveSkill[1], lv3);
                }
            }
        }
    }


    /**
     * 添加宠物属性
     * @param petConfigList 
     * @param mathValues 
     * @returns 
     */
    public static addPetMathByPetConfigList(
        petConfigList: number[],
        mathValues: number[]
    ): void {

        if (!petConfigList
            || petConfigList.length !== E_PetMonsterConfigIndex.EnumCount) {
            return;
        }

        const petConfigId = petConfigList[E_PetMonsterConfigIndex.PetConfigId];
        const petConfig = CDPet.getData(petConfigId);
        if (!petConfig) {
            return;
        }

        const petLevel = 1;
        const wakeLevel = 1;
        const evolutionLevel = petConfigList[E_PetMonsterConfigIndex.EvolutionLevel];

        //修改这边同步修改 this.addPetBaseAttrs
        //策划那边计算方便，没有配置的等级全部默认为 1
        SDPlayer.addMathConfig(CDMath.getData(petConfig.baseMath + petLevel), mathValues);
        SDPlayer.addMathConfig(CDMath.getData(petConfig.talentMath + evolutionLevel), mathValues);
        SDPlayer.addMathConfig(CDMath.getData(petConfig.wakeMath + wakeLevel), mathValues);
    }



}
